---
title: Metadata
description: How the title, description, and Open Graph images are configured in the CMS.
---

To generate metadata for a particular page or collection item, we can use the BaseHub SDK to query the metadata, then use Next.js' `generateMetadata` function to generate the metadata.

For example, here's how we've wired up the metadata for the blog post page, using the `createMetadata` function from the [SEO](/packages/seo/metadata) package:

```tsx apps/web/app/blog/[slug]/page.tsx
import { blog } from '@repo/cms';

type BlogPostProperties = {
  readonly params: Promise<{
    slug: string;
  }>;
};

export const generateMetadata = async ({
  params,
}: BlogPostProperties): Promise<Metadata> => {
  const { slug } = await params;
  const post = await blog.getPost(slug);

  if (!post) {
    return {};
  }

  return createMetadata({
    title: post._title,
    description: post.description,
    image: post.image.url,
  });
};
```

`blog.getPost` is a function that abstracts the logic of fetching the blog post from the CMS. Under the hood, it uses the BaseHub SDK to fetch the blog post from the CMS:

```tsx packages/cms/index.ts
import { basehub, fragmentOn } from 'basehub';

const postFragment = fragmentOn('PostsItem', {
  _slug: true,
  _title: true,
  authors: {
    _title: true,
    avatar: imageFragment,
    xUrl: true,
  },
  body: {
    plainText: true,
    json: {
      content: true,
      toc: true,
    },
    readingTime: true,
  },
  categories: {
    _title: true,
  },
  date: true,
  description: true,
  image: imageFragment,
});

export const blog = {
  // ...

  postQuery: (slug: string) => ({
    blog: {
      posts: {
        __args: {
          filter: {
            _sys_slug: { eq: slug },
          },
        },
        items: postFragment,
      },
    },
  }),

  getPost: async (slug: string) => {
    const query = blog.postQuery(slug);
    const data = await basehub().query(query);

    return data.blog.posts.items.at(0);
  },
};
```